<?php
/**
 * Created by PhpStorm.
 * User: zhaiyujin
 * Date: 2018/8/11
 * Time: 15:28
 */

//////////////////////////////////////Tool全局工具函数///////////////////////

/**
 * 功能:获取或设置配置参数值
 * @param null $name  键名
 * @param null $value  参数
 * @return array|mixed|null|void
 */
function C($name=null, $value=null) {
    static $_config = array();             //定义静态变量保存数据
    if (empty($name))   return $_config;   // 无参数时获取所有数据
    //优先执行设置获取或赋值
    //#获取或设置字符串相关操作
    if (is_string($name)) {                //判断传入字符串
        //##未搜索到xx.xx这样规则，一维数组设置
        if (!strpos($name, '.')) {   //key 字符串中没有发现.
            $name = strtolower($name);     //转换称小写
            if (is_null($value))           //参数为空，说明获取键名的内容，没有就返回空
                return isset($_config[$name]) ? $_config[$name] : null;
            $_config[$name] = $value;      //参数有值，说明需要设置值，通过静态变量键值对形式来保存
            return;
        }
        //##搜素到xx.xx, 二维数组设置和获取支持--[按规则最多只支持二维]
        $name = explode('.', $name); //搜寻到.按照规则分割数组
        $name[0]   =  strtolower($name[0]); //转换小写
        if (is_null($value))                //参数为空，获取二维数组内容
            return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : null;
        $_config[$name[0]][$name[1]] = $value; //不为空将参数内容赋值二维数组
        return;
    }
    // 数组，则是批量保存设置
    if (is_array($name)){
        return $_config = array_merge($_config, array_change_key_case($name));
    }
    return null; // 避免非法参数，我们直接返回null
}
/**
 * 功能：记录和统计时间(微秒)
 * 说明：通过全局变量，以及你传入值的方式，来记录统计时间。
 * @param $start
 * @param string $end
 * @param int $dec
 * @return string
 */
function G($start,$end='',$dec=4) {
    static $_info = array();
    if(is_float($end)) {        // 如果传入第二个参数并且是浮点数(字符串不行),表示记录时间
        $_info[$start]  =  $end;
    }elseif(!empty($end)){
        //如果是字符串之类，作为key 在全局变量中如果没有设置，则记录创建微秒数，如果局部变量中有值       //说明是统计计算微妙，并保留四位小数
        if(!isset($_info[$end])) $_info[$end]   =  microtime(TRUE);
        return number_format(($_info[$end]-$_info[$start]),$dec);
    }else{
        $_info[$start]  =  microtime(TRUE); //只值传递第一个值表示开始记录时间
    }
}
/**
 * 功能:获取和设置语言定义(不区分大小写)
 * @param null $name   键名
 * @param null $value  参数
 * @return array|mixed|string|void
 */
function L($name=null, $value=null) {
    static $_lang = array();
    if (empty($name)) return $_lang; // 空参数返回所有语言的定义数据
    // 判断语言获取(或设置)
    if (is_string($name)) {
        $name = strtoupper($name); //按规则键名大写。
        if (is_null($value))      // 若参数空的,直接查询键名对于的内容
            return isset($_lang[$name]) ? $_lang[$name] : $name;
        $_lang[$name] = $value;   // 参数有值，进行设置语言定义
        return;
    }
    // 数组，标识批量定义
    if (is_array($name))
        $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER));
    return; //不满足条件,非法数据不返回，不输出任何东西
}
/**
 * 功能：全局缓存设置和读取
 * 说明：根据传入不同的类型，生成相应功能的实例，通过变量名生成对应文件用来存储内容供变量读取，
 * @param $name            缓存名
 * @param string $value    缓存名的内容
 * @param null $expire     有效期
 * @param string $type     功能类
 * @param null $options    提供给功能类功能参数
 * @return mixed|string|void
 */
function S($name, $value='', $expire=null, $type='',$options=null) {
    static $_cache = array();
    //取得缓存对象实例
    $cache = Cache::getInstance($type,$options); //创建缓存对象实例
    if ('' !== $value) {                         //参数不为空字符串
        if (is_null($value)) {                   //参数为null
            // 删除缓存
            $result = $cache->rm($name);         //代表清除该缓存，调用实例rm方法删除缓存文件
            if ($result)
                unset($_cache[$type . '_' . $name]);  //清除缓存文件后，清除静态变量保存的内容
            return $result;                      //返回清除成功的boolean值
        }else {

            $cache->set($name, $value, $expire);  //有参数，为缓存变量设置缓存
            $_cache[$type . '_' . $name] = $value; //并将键值保存静态变量中
        }
        return;
    }
    if (isset($_cache[$type . '_' . $name]))    //如果该缓存变量设置过
        return $_cache[$type . '_' . $name];    //直接从静态变量中读取缓存变量保存的内容
    //一般情况,设置缓存都会保存静态变量中,可直接获取.一个生命周期结束后静态变量会失效，这样，只能通过get来通过文件获取
    $value = $cache->get($name);           //
    $_cache[$type . '_' . $name] = $value; //将结果保存静态数组中
    return $value;
}
/**
 * 功能：快速文件数据读取和保存 针对简单类型数据 字符串、数组
 * 说明：在指定缓存路径下生成 $name.php来存放我们变量的内容，支持层级子目录层级 $name="/test/data"；
 * 在data.php。放入内容，内容按规则存入文件，供我们随时读取。
 * @param $name
 * @param string $value
 * @param $path
 * @return bool|int|mixed|string
 */
function F($name, $value='', $path=DATA_PATH) {
    static $_cache = array();
    $filename = $path . $name . '.php';     //拼接文件全路径
    if ('' !== $value) {
        if (is_null($value)) {              //设置null表示删除文件
            // 删除缓存
            return unlink($filename);
        } else {                           //有值
            // 缓存数据
            $dir = dirname($filename);     //得到文件目录
            // 目录不存在则创建
            if (!is_dir($dir))             //未找到目录创建目录
                mkdir($dir);
            $_cache[$name] =   $value;     //保存到静态变量中
            return file_put_contents($filename, strip_whitespace("<?php\nreturn " . var_export($value, true) . ";\n?>"));
        }
    }
    if (isset($_cache[$name]))           //从静态获取缓存内容
        return $_cache[$name];
    // 获取缓存数据
    if (is_file($filename)) {             //如果通过手动添加或者,静态变量一次请求生命周期后会失效，此时 可以直接从文件中获取，来提高效率，并添加到静态文件中
        $value = include $filename;
        $_cache[$name] = $value;
    } else {
        $value = false;
    }
    return $value;
}
/**
 * 功能：设置和获取统计数据
 * @param $key
 * @param int $step
 * @return mixed
 */
function N($key, $step=0) {
    static $_num = array();
    if (!isset($_num[$key])) {//没有设置该键名的内容
        $_num[$key] = 0;       //默认赋值0
    }
    if (empty($step))        //参数为空表示获取内容
        return $_num[$key];
    else
        $_num[$key] = $_num[$key] + (int) $step;  //累加统计
}
/**
+----------------------------------------------------------
 * D函数用于实例化Model 格式 项目://分组/模块
+----------------------------------------------------------
 * @param string name Model资源地址
+----------------------------------------------------------
 * @return Model
+----------------------------------------------------------
 */
function D($name='') {
    if(empty($name)) return new Model;
    static $_model = array();
    if(isset($_model[$name]))
        return $_model[$name];
    if(strpos($name,'://')) {// 指定项目
        $name   =  str_replace('://','/Model/',$name);
    }else{
        $name   =  C('DEFAULT_APP').'/Model/'.$name;
    }
    import($name.'Model');
    $class   =   basename($name.'Model');
    if(class_exists($class)) {
        $model = new $class();
    }else {
        $model  = new Model(basename($name));
    }
    $_model[$name]  =  $model;
    return $model;
}

/**
+----------------------------------------------------------
 * M函数用于实例化一个没有模型文件的Model
+----------------------------------------------------------
 * @param string name Model名称 支持指定基础模型 例如 MongoModel:User
 * @param string tablePrefix 表前缀
 * @param mixed $connection 数据库连接信息
+----------------------------------------------------------
 * @return Model
+----------------------------------------------------------
 */
/**
 * 功能：M函数可以用于实例化一个没有模型文件的model
 * @param string $name 模型名称名称  可以使用指定模型中实例 例如 MongoModel:User
 * @param string $tablePrefix   表前缀
 * @param string $connection    数据库连接信息
 * @return mixed
 */
function M($name='', $tablePrefix='',$connection='') {
    static $_model = array();
    //判断使用指定或者默认模型名。
    if(strpos($name,':')) {
        list($class,$name)    =  explode(':',$name);
    }else{
        $class   =   'Model';
    }
    //创建model模型或者指定模型类的实例
    if (!isset($_model[$name . '_' . $class]))
        $_model[$name . '_' . $class] = new $class($name,$tablePrefix,$connection);

    //返回该模型的实例
    return $_model[$name . '_' . $class];
}

/**
 * 功能：通过url 模块/操作 来执行项目中对应的文件
 * URL 参数格式 [项目://][分组/]模块/操作
 * @param $url   /Index/index  为例子 index文件名basename  /Index则为文件目录
 * @param array $vars
 * @return bool|mixed
 */
function R($url,$vars=array()) {
    $info =  pathinfo($url);
    $action  =  $info['basename'];//获得文件名称
    $module =  $info['dirname'];  //获得文件目录
    $class = A($module);
    if($class)
        return call_user_func_array(array($class,$action),$vars);
    else
        return false;
}

/**
 * 功能：A函数用于按照规则,加载类文件，并且进行实例化(缓存数据)
 * 说明：Action格式 [项目://][分组/]模块    [项目@/Action][分组/]模块
 * @param $name
 * @return bool|mixed
 */
function A($name) {
    static $_action = array();

    if(isset($_action[$name]))
        return $_action[$name];

    //两种规则搜寻类库的方式，第一种是://  第二种是@
    if(strpos($name,'://')) {// 指定项目
        $name   =  str_replace('://','/Action/',$name);
    }else{
        $name   =  '@/Action/'.$name;
    }
    //导入类库
    import($name.'Action');

    //根据规则获取类名
    $class   =   basename($name.'Action');

    //类被导入则实例化，将实例化的内容报错到静态变量中
    if(class_exists($class,false)) {
        $action = new $class();
        $_action[$name]  =  $action;
        return $action;
    }else {
        return false;
    }
}


/**
 * 功能：导入所需要的类(类似java的Import)
 * 本函数有缓存功能，通过静态变量实现的单例
 * @param $class            类库命名特殊字符串
 * @param string $baseUrl   起始路径
 * @param string $ext       导入的文件扩展名
 * @return bool|mixed|void
 * 以 @/Action/Index为例子
 */
function import($class, $baseUrl = '', $ext='.class.php') {
    static $_file = array();
    //将类库名称字符串.替换成/   #替换成.
    $class = str_replace(array('.', '#'), array('/', '.'), $class);

    //传入起始路径为空，类库名未搜到/ 检查别名，变量存储过直接引入类库文件
    if ('' === $baseUrl && false === strpos($class, '/')) {
        return alias_import($class);
    }

    //将类库命名字符串拼接起始路径，判断是否导入过，导入过直接返回，否则设置类库导入标志
    if (isset($_file[$class . $baseUrl]))
        return true;
    else
        $_file[$class . $baseUrl] = true;

    //将字符串中带有/分割成数组
    $class_strut = explode('/', $class);

    //未设置过起始路径
    if (empty($baseUrl)) {
        //类库命名中以@开头或者第一个就是项目根目录
        if ('@' == $class_strut[0] || APP_NAME == $class_strut[0]) {
            //加载当前项目应用类库
            $baseUrl = dirname(LIB_PATH);
            //以@/Action/Index为例子从0开始查找两个长度字符也就是@/ 把他们替换成lib/ 得到lib/action/index。
            $class = substr_replace($class, basename(LIB_PATH).'/', 0, strlen($class_strut[0]) + 1);

            //如果开头是think  列如think/ddd/xxxx  表示载入的这个类是当前系统的基类
        }elseif ('think' == strtolower($class_strut[0])){

            //得到系统核心类库路径
            $baseUrl = CORE_PATH;
            //将think/部分给截取掉得到后面的部分
            $class = substr($class,6);

            //判断开头的前缀是否在数组中，以org或者com开头
        }elseif (in_array(strtolower($class_strut[0]), array('org', 'com'))) {

            // org 第三方公共类库 com 企业公共类库
            $baseUrl = LIBRARY_PATH;

        }else {
            // 加载其他项目应用类库 ,把前缀部分去除
            $class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);
            //注意这个类库要与我们的项目同级
            $baseUrl = APP_PATH . '../' . $class_strut[0] . '/'.basename(LIB_PATH).'/';
        }
    }

    //如果结尾没有/要补充斜线
    if (substr($baseUrl, -1) != '/')
        $baseUrl .= '/';

    //拼接类的路径地址 例如 lib/Action/Index.class.php
    $classfile = $baseUrl . $class . $ext;

    //获取文件名 例如Index检查类是否存在
    if (!class_exists(basename($class),false)) {
        // 如果类不存在 则尝试导入类库文件的路径
        return require_cache($classfile);
    }
}

/**
 * 功能: 根据PHP各种类型变量生成唯一标识号
 * 使用函数解析:
 * spl_object_hash:指定对象返回唯一标识hashid,每一个对象他都是唯一的,但是同一个对象(对象赋值)他们是相同的.需要注意的是如果*象销毁了,这个hashid可能用于其他对象.
 *
 *get_resource_type:能够获得资源是哪种类型例子:
 *$c=mysql_connect(); echo get_resource_type($c);//mysql link
 *$fp=fopen("foo","w"); echo get_resource_type($fp); //file
 * $doc=new_xmldoc("1.0"); echo get_resource_type($doc->doc) //domxml document
 *
 * strval() //获取变量字符串值, 例子:变量数字2变成"2",true 变成"1"...不能用于数组或对象
 * @param $mix
 * @return string
 */
function type_to_along_string($mix) {
    if (is_object($mix) && function_exists('spl_object_hash')) { //对象类型
        return spl_object_hash($mix);
    } elseif (is_resource($mix)) {        //资源类型
        $mix = get_resource_type($mix) . strval($mix);
    } else {
        $mix = serialize($mix);     //其他类型
    }
    return md5($mix);
}
/**
 * 功能：url重定向
 * 关键函数：headers_sent
 * 功能说明：检查 HTTP 标头是否已被发送，如果报头已发送，则返回 true，否则返回 false
 * 为什么要使用该函数：
 * 1.在发送header头之前不能有任何输出，空格也不行,你需要将header(...)之前的空格去掉,或者其他输出的东西去掉。
 * 2.如果他上面include其他文件了，你还要检查其他文件里是否有输出， 若有任何輸出, 就會有下述的錯誤訊息: Cannot modify header information。。。。
 * 3.使用该函数，我们可以进行判断包头发送情况，如果已经发送，我们使用meta标签来刷新页面。如果没有发送我们使用header头来重定向
 * 4.使用echo来模拟上面输出，记得ob_flush,flush.
 * @param $url
 * @param int $time
 * @param string $msg
 */
function redirect($url, $time=0, $msg='') {
    //使用文本等保存的url,取出时url很可能后面会带有\n\r,需要将他去除
    $url = str_replace(array("\n", "\r"), '', $url);
    if (empty($msg))
        $msg = "系统将在{$time}秒之后自动跳转到{$url}！";
    if (!headers_sent()) {
        // redirect
        if (0 === $time) {
            header('Location: ' . $url);
        } else {
            header("refresh:{$time};url={$url}");//隔几秒跳转
            echo($msg); //延迟,会先输出$msg
        }
        exit();
    } else {
        $str = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
        if ($time != 0)
            $str .= $msg;  //延迟，先输出内容附带内容
        exit($str);        //直接刷新指定页面
    }
}
/**
 * 功能：require_once影响性能,使用require来载入，用静态变量来保存已载入的文件
 * @param $filename
 * @return mixed 成功载入返回true
 */
function require_cache($filename) {
    static $_importFiles = array();
    if (!isset($_importFiles[$filename])) {//没有载入过此文件
        if (file_exists_case($filename)) { //判断文件是否存在
            require $filename;
            $_importFiles[$filename] = true;
        } else {
            $_importFiles[$filename] = false;
        }
    }
    return $_importFiles[$filename];
}
/**
 * 功能:是否对windows中文件大小写进行检查判断
 * basename:获取路径中文件名的部分---xxx.php
 * realpath:获取文件的绝对路径
 * @param $filename
 * @return bool
 */
function file_exists_case($filename) {
    if (is_file($filename)) {
        if (IS_WIN && C('APP_FILE_CASE')) { //如果是windows且需要检查文件大小才执行
            if (basename(realpath($filename)) != basename($filename))
                return false;
        }
        return true;
    }
    return false;
}
/**
 * 功能：自定义异常处理
 * @param $msg
 * @param string $type
 * @param int $code
 */
function throw_exception($msg, $type='ThinkException', $code=0) {
    //先判断是否有自定义异常处理类，如果有自定义类。我们使用自定义异常类
    if (class_exists($type, false))
        try{
            throw new $type($msg, $code, true);
        }catch(Exception $e){

            echo $e;
        }

    else
        halt($msg);        // 异常类型不存在则输出错误信息字串
}
/**
 * 功能：跟踪回调信息，错误信息的输出
 * 详细：开启debug模式，传入的不是数组，获取debug跟踪信息，如果是数组记录这个数组。
 *      未开启debug,查找是否有自定义模板，有就跳转到这个模板，如果未设置模板，是否允许输出错误信息，不允许输出，自定义的错误信息。允许输出记录传入的数组或者字符串。供模板使用
 * debug_backtrace函数说明：能够获取到当前某段代码是被哪个方法调用，并能一直回溯到最开始调用的地方（包括调用的文件，行数，参数等
 * @param $error
 */
function halt($error) {
    $e = array();
    if (APP_DEBUG) {             //debug开启输出信息
        //调试模式下输出错误信息
        if (!is_array($error)) {
            $trace = debug_backtrace();
            $e['message'] = $error;
            $e['file'] = $trace[0]['file'];
            $e['class'] = $trace[0]['class'];
            $e['function'] = $trace[0]['function'];
            $e['line'] = $trace[0]['line'];
            $traceInfo = '';
            $time = date('y-m-d H:i:m');
            foreach ($trace as $t) {
                $traceInfo .= '[' . $time . '] ' . $t['file'] . ' (' . $t['line'] . ') ';
                $traceInfo .= $t['class'] . $t['type'] . $t['function'] . '(';
                $traceInfo .= implode(', ', $t['args']);
                $traceInfo .=')<br/>';
            }
            $e['trace'] = $traceInfo;
        } else {
            $e = $error;
        }
        // 包含异常页面模板
        include C('TMPL_EXCEPTION_FILE');
    } else {        //否则定向到错误页面

        $error_page = C('ERROR_PAGE');  //获取自定义错误
        if (!empty($error_page)) {
            redirect($error_page);          //存在自定义错误页面直接跳转到页面
        } else {
            if (C('SHOW_ERROR_MSG'))   //是否显示错误信息
                $e['message'] = is_array($error) ? $error['message'] : $error;
            else
                $e['message'] = C('ERROR_MESSAGE'); //不显示错误信息，显示默认信息
            // 包含异常页面模板
            include C('TMPL_EXCEPTION_FILE');     //在错误页面模板显示
        }
    }
    exit;
}
/**
 * 功能:取得对象实例，支持调用类的静态方法
 * 使用环境：传入类名或方法名或参数，调用其方法并返回方法中创建的实例并保存
 * @param $name           类名
 * @param string $method  方法
 * @param array $args     参数
 * @return mixed   返回对象实例
 */
function get_instance_of($name, $method='', $args=array()) {
    static $_instance = array();       //静态变量来保存对象实例
    //生成一个唯一标识的key与实例对应
    $identify = empty($args) ? $name . $method : $name . $method . type_to_along_string($args);
    if (!isset($_instance[$identify])) {      //根据标识查找实例
        if (class_exists($name)) {            //判断类是否存在
            $o = new $name();                 //类存在
            if (method_exists($o, $method)) { //判断类方法是否存在
                if (!empty($args)) {          //带有参数
                    $_instance[$identify] = call_user_func_array(array(&$o, $method), $args);
                } else {
                    $_instance[$identify] = $o->$method();//没有参数直接调用方法
                }
            }
            else
                $_instance[$identify] = $o; //方法不存在，保存当前实例
        }
        else
            halt(L('_CLASS_NOT_EXIST_') . ':' . $name);//报错误并指定方位
    }
    return $_instance[$identify];
}
/**
 * 功能：定义别名对应的文件路径(支持数组批量)，快速导入别名(载入别名对应的文件)
 * 说明：当$alias是数组["别名"=>"对应绝对路径”] 直接合并赋值全局变量
 *      当$alias是字符串，全局变量中存在，直接载入。不存在如果设置对于绝对路径$classfile将其赋值给对应别名
 * @param $alias
 * @param string $classfile
 * @return bool|mixed|void
 */
function alias_import($alias, $classfile='') {
    static $_alias = array();
    if (is_string($alias)) {            //别名是字符串
        if(isset($_alias[$alias])) {    //全局变量中如果设置过
            return require_cache($_alias[$alias]); //载入文件，成功返回true
        }elseif ('' !== $classfile) {   //全局变量未设置，设置别名带有文件
            // 定义别名导入
            $_alias[$alias] = $classfile; //定义别名并赋值对于文件路径
            return;
        }
    }elseif (is_array($alias)) {         //别名传入的是数组
        $_alias   =  array_merge($_alias,$alias);  //将别名对于键值进行合并
        return;
    }
    return false;
}
/**
 * 功能：循环创建目录
 * 说明：创建多级目录的时候,如果上层目录不存在，创建目录会出错，通过@来抑制错误,递归调用父目录
 * 如果其父目录仍不存在，继续递归，如果此时上级目录都存在，成功创建目录，并返回true.到上一层
 * 递归非true就是假，执行mkdir(..) 成功返回true，并返回给上一层递归，这样一个个创建，如果递归过 * 程中有一个创建失败则返回false这样会造成，接下来的创建都是失败最后返回false
 * @param $dir
 * @param int $mode
 * @return bool
 */
function mk_dir($dir, $mode = 0777) {
    if (is_dir($dir) || @mkdir($dir, $mode)) //是目录无需创建目录，不是目录则创建目录
        return true;
    if (!mk_dir(dirname($dir), $mode)) //如果无法创建说明上级没有创建目录需要到上级创建目录
        return false;
    return @mkdir($dir, $mode);
}
/**
 * 功能：tp文件编译,获取文件内容
 * 说明：读取文件并截取<?php ?>中的内容,如果存在编译指令替换空字符串
 * @param $filename 文件名
 * @return bool|mixed|string
 */
function compile($filename) {
    $content = file_get_contents($filename);
    // 替换预编译指令
    $content = preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content);
    $content = substr(trim($content), 5);
    if ('?>' == substr($content, -2))
        $content = substr($content, 0, -2);
    return $content;
}
/**
 * 功能：去除代码中的空白和注释
 * 说明：通过token_get_all这个函数分割代码段。来处理调里面的空白和注释，
 * 对于这个函数不懂看笔记，笔记有记载。
 * @param $content
 * @return string
 */
function strip_whitespace($content) {
    $stripStr = '';
    $tokens = token_get_all($content);//使用该函数来分割代码
    $last_space = false;
    for ($i = 0, $j = count($tokens); $i < $j; $i++) {    //统计有多少个片段，循环处理这些片段
        if (is_string($tokens[$i])) {     //特殊字符不会以数组形式程序会直接输出比如; =等等
            $last_space = false;
            $stripStr .= $tokens[$i];     //把这些特殊字符拼接到后面
        } else {
            switch ($tokens[$i][0]) {     //二维数组，这代表了每一个代号
                //过滤各种PHP注释，遇到注释直接跳过
                case T_COMMENT:
                case T_DOC_COMMENT:
                    break;
                //过滤空格
                case T_WHITESPACE:
                    if (!$last_space) {  //例子：1 => string '           ' (length=11) 过滤调这么长的空格使用一个字符长度空格来代替，不要使用''这个哦，代码不能连接在一起会出错的哦
                        $stripStr .= ' ';
                        $last_space = true;
                    }
                    break;
                case T_START_HEREDOC:  //如果使用了heredoc 语法，那么替换成我们的
                    $stripStr .= "<<<THINK\n";
                    break;
                case T_END_HEREDOC:
                    $stripStr .= "THINK;\n";
                    for($k = $i+1; $k < $j; $k++) { //判断后面是否以;结尾还是 闭合标签 ? >或 %>
                        if(is_string($tokens[$k]) && $tokens[$k] == ';') {
                            $i = $k;
                            break;
                        } else if($tokens[$k][0] == T_CLOSE_TAG) {
                            break;
                        }
                    }
                    break;
                default:
                    $last_space = false;
                    $stripStr .= $tokens[$i][1];   //未匹配到这些，我们拼接代码片段原始内容。
            }
        }
    }
    return $stripStr;
}
/**
 * 功能：字符串命名风格转换 驼峰命名转换
 * =0 将Java风格转换为C的风格
 * =1 将C风格转换为Java的风格 (驼峰命名法)
 * 解析说明: 第一种例子：_list  会匹配到_list ,获取list内容全小写，再将首字母大写得到List----->使用List来替换原来的_list
 *
 *          第二种例子：ToList  会匹配到T和L，分别进行处理替换，都在在匹配的内容前面_ ，然后替换原来的内容_To_List .在转换成小写去除两边下横线得到to_list标准的驼峰命名法规则。
 * @param $name
 * @param int $type
 * @return string
 */
function parse_name($name, $type=0) {
    if ($type) {
        //return ucfirst(preg_replace("/_([a-zA-Z])/e", "strtoupper('\\1')", $name)); e模式5.5后版本已经不推荐使用，请使用preg_replace_callback
        return preg_replace_callback("/_([a-zA-Z])/",function($pattern){
            return ucfirst(strtoupper($pattern[1]));
        },$name);
    } else {
        //return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));

        return strtolower(trim(preg_replace_callback("/[A-Z]/",function($pattern){
            return "_".$pattern[0];
        },$name),"_"));
    }
}

///////////////////////////////Tool全局工具函数////////////////////////////